﻿using System.ServiceModel.Channels;
using System.ServiceModel;
using System;
using System.ServiceModel.Description;
using System.Windows;
using System.ComponentModel;
using System.Text;
using System.Reflection;
using Ops.Mpc.Events;
using System.Linq;
using System.Threading;
using System.Net;


namespace Ops.Mpc.Wcf
{

    public class ServiceContext<ServiceClientType,ChannelType> where ServiceClientType : ClientBase<ChannelType> where ChannelType : class
    {
        #region Fields & Properties
        private ServiceClientType _serviceClient = default(ServiceClientType);

        protected ServiceClientType ServiceClient
        {
            get
            {
                return this._serviceClient;
            }

            set
            {
                this._serviceClient = value;

                if (this._serviceClient != null)
                {
                    this.AddServiceHeaderBehavior(this._serviceClient.Endpoint);

                    IHttpCookieContainerManager cookieManager = _serviceClient.InnerChannel.GetProperty<IHttpCookieContainerManager>();

                    if (cookieManager.CookieContainer == null)
                        cookieManager.CookieContainer = new CookieContainer();

                }
            }
        }

        protected ChannelType Service
        {
            get
            {
                return this._serviceClient as ChannelType;
            }
        }


        #endregion

        #region Constructors
        protected ServiceContext()
        {

        }
        #endregion 

        #region Methods

        protected virtual EndpointAddress GetEndpointAddress()
        {
            EndpointAddress endpointAddress = new EndpointAddress(this.GetServiceUri());
            return endpointAddress;
        }

        protected virtual Binding GetBasicHttpBinding()
        {
            BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
  
            basicHttpBinding.MaxBufferSize = int.MaxValue;
            basicHttpBinding.MaxReceivedMessageSize = int.MaxValue;
            basicHttpBinding.ReceiveTimeout = TimeSpan.FromMinutes(3);
            basicHttpBinding.SendTimeout = TimeSpan.FromMinutes(3);
            basicHttpBinding.OpenTimeout = TimeSpan.FromMinutes(3);
            basicHttpBinding.EnableHttpCookieContainer = true;


            return basicHttpBinding;

        }

        protected virtual void AddServiceHeaderBehavior(ServiceEndpoint serviceEndpoint)
        {
            serviceEndpoint.Behaviors.Add(new ServiceHeaderBehavior());
        }


 
        protected virtual Binding GetBinaryBinding()
        {

            BinaryMessageEncodingBindingElement binaryMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
            HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
            HttpCookieContainerBindingElement httpCookieContainerBindingElement = new HttpCookieContainerBindingElement();

            CustomBinding binding = new CustomBinding(httpCookieContainerBindingElement, binaryMessageEncodingBindingElement, httpTransportBindingElement);

            httpTransportBindingElement.MaxBufferSize = int.MaxValue;
            httpTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;


            binding.ReceiveTimeout = TimeSpan.FromMinutes(3);
            binding.SendTimeout = TimeSpan.FromMinutes(3);
            binding.OpenTimeout = TimeSpan.FromMinutes(3);

            return new CustomBinding(binding);

        }

        protected virtual Binding GeTextBinding()
        {

            TextMessageEncodingBindingElement textMessageEncodingBindingElement = new TextMessageEncodingBindingElement();
            HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
            HttpCookieContainerBindingElement httpCookieContainerBindingElement = new HttpCookieContainerBindingElement();

            CustomBinding binding = new CustomBinding(httpCookieContainerBindingElement, textMessageEncodingBindingElement, httpTransportBindingElement);

            httpTransportBindingElement.MaxBufferSize = int.MaxValue;
            httpTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;


            binding.ReceiveTimeout = TimeSpan.FromMinutes(3);
            binding.SendTimeout = TimeSpan.FromMinutes(3);
            binding.OpenTimeout = TimeSpan.FromMinutes(3);

            return new CustomBinding(binding);

        }

        protected virtual string GetServerUri()
        {
            int index = Application.Current.Host.Source.AbsoluteUri.IndexOf("/ClientBin");

            if (index < 0)
                throw new Exception("Could not find ClientBin, you must run application from a website");

            Uri uri = new Uri(Application.Current.Host.Source.AbsoluteUri.Substring(0,index ));
            return uri.AbsoluteUri.TrimEnd('/');
        }

        protected virtual string GetServiceUri()
        {
            throw new NotImplementedException("Please implement GetServiceUri()");
        }


        protected AsyncCallback GetAsyncCallback<ResultType>(AsyncEndHandler<ResultType> asyncEndHandler, AsyncCompleteHandler<ResultType> asyncCompleteHandler, ErrorHandler errorHandler, bool enableCancel = false)
        {
            CancelContext cancelContext = enableCancel ? new CancelContext(errorHandler) : null;

            return (IAsyncResult iAsyncResult) => 
            {
                using (cancelContext)
                {
                    ResultType result = default(ResultType);

                    try
                    {
                        result = asyncEndHandler(iAsyncResult);
                    }
                    catch (Exception exception)
                    {
                        if ((cancelContext == null || !cancelContext.Cancelled)&& errorHandler != null)
                        {
                            System.Windows.Deployment.Current.Dispatcher.BeginInvoke(errorHandler, exception.Message, exception);
                        }

                        return;
                    }

                    if ((cancelContext == null || !cancelContext.Cancelled) && asyncCompleteHandler != null)
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(asyncCompleteHandler, result, iAsyncResult.AsyncState);
                }
            
            };
        }


         #endregion
    }
}
